package logger

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"sync"
	"time"
)

const (
	logLengthMax = 1024
)

type Logger struct {
	mu  sync.Mutex
	out io.Writer
}

func (l *Logger) Output(calldepth int, s string) error {
	var now string
	l.mu.Lock()
	defer l.mu.Unlock()
	now = time.Now().Format("01/02 15:04:05.000")

	if len(s) > logLengthMax {
		s = string([]byte(s)[:logLengthMax]) + "...\n"
	}

	_, file, line, ok := runtime.Caller(calldepth)
	if !ok {
		file = "???"
		line = 0
	} else {
		file = filepath.Base(file)
	}

	logBuf := fmt.Sprintf("%s [%s:%d] %s", now, file, line, s)
	_, _ = l.out.Write([]byte(logBuf))
	return nil
}

var std = &Logger{out: os.Stderr}

func Trace(format string, v ...interface{}) {
	now := time.Now().Format("01/02 15:04:05.000")
	s := fmt.Sprintf(format+"\n", v...)
	if len(s) > logLengthMax {
		s = string([]byte(s)[:logLengthMax]) + "...\n"
	}
	fmt.Printf(fmt.Sprintf("%s %s", now, s))
}

func Debug(format string, v ...interface{}) {
	_ = std.Output(2, fmt.Sprintf(format+"\n", v...))
}

func Println(format string, v ...interface{}) {
	_ = std.Output(2, fmt.Sprintf(format+"\n", v...))
}

func Info(format string, v ...interface{}) {
	_ = std.Output(2, fmt.Sprintf("\033[32;1m"+format+"\033[0m\n", v...))
}

func Warn(format string, v ...interface{}) {
	_ = std.Output(2, fmt.Sprintf("\033[33;1m"+format+"\033[0m\n", v...))
}

func Error(format string, v ...interface{}) {
	_ = std.Output(2, fmt.Sprintf("\033[31;1m"+format+"\033[0m\n", v...))
}

func Panic(format string, v ...interface{}) {
	_ = std.Output(2, fmt.Sprintf("\033[31;1m"+format+"\033[0m\n", v...))
}

func Fatal(format string, v ...interface{}) {
	_ = std.Output(2, fmt.Sprintf("\033[31;1m"+format+"\033[0m\n", v...))
}
